//////////////////////////////////////////////////////////////////////////
//
// This file is a part of UKROP project.
// Copyright (c) Vladimir Gumenuk
//
// PROJECT:         Xort Custom Debug Engine
// FILE:            DebugStack.cpp
// AUTHOR:          Vladimir Gumenuk
// DATE:            8-Jan-2013
// MODIFICATIONS:
//
//////////////////////////////////////////////////////////////////////////

#include "stdafx.h"
#include "xort.h"
#include "xruntime.h"
#include "DebugProperty.h"
#include "DebugStack.h"

//////////////////////////////////////////////////////////////////////////
// helper
CFrameInfo::CFrameInfo()
{
    m_dwRefCount = 0;
    Zero( *this );
}

CFrameInfo::CFrameInfo( FRAMEINFO& fr )
{
    Zero( *this );
    Copy( *this, fr );
}

CFrameInfo::~CFrameInfo()
{
    Clear( *this );
}

DWORD CFrameInfo::AddRef()
{
    return ++m_dwRefCount;
}

DWORD CFrameInfo::Release()
{
    if( --m_dwRefCount == 0 ) {
        delete this;
        return 0;
    }
    return m_dwRefCount;
}

void CFrameInfo::operator= ( FRAMEINFO& fr )
{
    if( this == &fr ) return;
    Clear( *this );
    Copy( *this, fr );
}

void CFrameInfo::Copy( FRAMEINFO& frDst, FRAMEINFO& frSrc )
{
    frDst.m_dwValidFields = frSrc.m_dwValidFields;

    if( frSrc.m_bstrFuncName && ( frSrc.m_dwValidFields & FIF_FUNCNAME ) ) 
        frDst.m_bstrFuncName = SysAllocString( frSrc.m_bstrFuncName );

    if( frSrc.m_bstrReturnType && ( frSrc.m_dwValidFields & FIF_RETURNTYPE ) )
        frDst.m_bstrReturnType = SysAllocString( frSrc.m_bstrReturnType );

    if( frSrc.m_bstrArgs && ( frSrc.m_dwValidFields & FIF_ARGS ) )
        frDst.m_bstrArgs = SysAllocString( frSrc.m_bstrArgs );

    if( frSrc.m_bstrLanguage && ( frSrc.m_dwValidFields & FIF_LANGUAGE ) )
        frDst.m_bstrLanguage = SysAllocString( frSrc.m_bstrLanguage );

    if( frSrc.m_bstrModule && ( frSrc.m_dwValidFields & FIF_MODULE ) )
        frDst.m_bstrModule = SysAllocString( frSrc.m_bstrModule );

    frDst.m_addrMin = frSrc.m_addrMin;
    frDst.m_addrMax = frSrc.m_addrMax;

    if( frSrc.m_pFrame && ( frSrc.m_dwValidFields & FIF_FRAME ) )
    {
        frDst.m_pFrame = frSrc.m_pFrame;
        frDst.m_pFrame->AddRef();
    }

    if( frSrc.m_pModule && ( frSrc.m_dwValidFields & FIF_DEBUG_MODULEP ) )
    {
        frDst.m_pModule = frSrc.m_pModule;
        frDst.m_pModule->AddRef();
    }

    frDst.m_fHasDebugInfo = frSrc.m_fHasDebugInfo;
    frDst.m_fStaleCode    = frSrc.m_fStaleCode;
    frDst.m_dwFlags       = frSrc.m_dwFlags;
}

void CFrameInfo::Clear( FRAMEINFO& fr )
{
    fr.m_dwValidFields     = 0;
    SAFE_FREESTR( fr.m_bstrFuncName );
    SAFE_FREESTR( fr.m_bstrReturnType );
    SAFE_FREESTR( fr.m_bstrArgs );
    SAFE_FREESTR( fr.m_bstrLanguage );
    SAFE_FREESTR( fr.m_bstrModule );
    fr.m_addrMin           = 0;
    fr.m_addrMax           = 0;
    SAFE_RELEASE( fr.m_pFrame );
    SAFE_RELEASE( fr.m_pModule );
    fr.m_fHasDebugInfo     = FALSE;
    fr.m_fStaleCode        = FALSE;
    fr.m_dwFlags           = 0;
}

void CFrameInfo::Zero( FRAMEINFO& fr )
{
    fr.m_dwValidFields     = 0;
    fr.m_bstrFuncName      = NULL;
    fr.m_bstrReturnType    = NULL;
    fr.m_bstrArgs          = NULL;
    fr.m_bstrLanguage      = NULL;
    fr.m_bstrModule        = NULL;
    fr.m_addrMin           = 0;
    fr.m_addrMax           = 0;
    fr.m_pFrame            = NULL;
    fr.m_pModule           = NULL;
    fr.m_fHasDebugInfo     = FALSE;
    fr.m_fStaleCode        = FALSE;
    fr.m_dwFlags           = 0;
}

void CFrameInfo::FormatFunctionArgs( UINT nRadix, Symbol *pProc, DWORD dwStackBase, SYMBOLLIST listGlobal,  XRuntime *pRT )
{
    // can't format argument values without knowing what radix to use... now it is time to do this

    XCELLSARRAY& retStack   = pRT->get_ReturnStack();
    XCELLSARRAY& arithStack = pRT->get_Stack();

    XortElement& sysFrame = arithStack.get( dwStackBase );
    DWORD dwArgsCount = sysFrame.bType;
    DWORD dwArgIdx = dwStackBase - dwArgsCount;

    SYMBOL_LIST::iterator theIter = pProc->m_listMembers.end();
    theIter--; // skip local scope marker
    symbolref pArg = ( theIter == NULL ) ? NULL : (Symbol*)theIter;

    string csArgs;
    dword i = 0;
    while( dwArgsCount ) // format arguments:
    {
        char szBuf[MAX_PATH];

        if( pArg )
        {
            SymbolRef argType   = FindType( listGlobal, pArg->m_dwType );
            XortElement& argVal = arithStack.get( (DWORD)( (int)dwStackBase + pArg->m_iIndex ) );
            string csVal        = xFormatElementValue( argVal, nRadix );
            sprintf( szBuf, "%s %s(%s)", argType.m_csName.GetBuffer(), pArg->m_csName.GetBuffer(), csVal.GetBuffer() );

        } else { // function with unspecified number of args, get the arg type from stack cell...
            XortElement& argVal = arithStack.get( dwArgIdx );
            string csTypeName;
            if( argVal.bType == t_p ) {
                if( argVal._p != NULL ) {
                    xobject *pObj = (xobject*)argVal._p;
                    SymbolRef argType = FindType( listGlobal, pObj->GetType() );
                    csTypeName = argType.m_csName;
                } else {
                    csTypeName = "object";
                }
            } else {
                SymbolRef argType = FindType( listGlobal, argVal.bType );
                csTypeName = argType.m_csName;
            }

            string csVal = xFormatElementValue( argVal, nRadix );
            sprintf( szBuf, "%s _s%d(%s)", csTypeName, ++i, csVal.GetBuffer() );
        }

        csArgs.Add( szBuf );
        dwArgsCount--;
        if( dwArgsCount > 0 ) {
            csArgs.Add( ", ");
        }

        dwArgIdx++;
        theIter--;
        pArg = ( theIter == NULL ) ? NULL : (Symbol*)theIter;
        if( pArg && pArg->m_csName.Compare( "$" ) == 0 ) { // handle unspecified number of arguments marker
            pArg = NULL;
        }
    }

    SAFE_FREESTR( m_bstrArgs );

    if( sysFrame.bType && csArgs.Length() )
    {
        m_bstrArgs = CComBSTR( csArgs.GetBuffer() ).Detach();
        m_dwValidFields |= FIF_ARGS_TYPES | FIF_ARGS_NAMES | FIF_ARGS_VALUES;
    } else {
        m_dwValidFields &= ~(FIF_ARGS_TYPES | FIF_ARGS_NAMES | FIF_ARGS_VALUES);
    }
}


void CDebugStackCell::ReleaseCrossRefs()
{
    if( m_pFrameInfo )
    {
        if( m_pFrameInfo->m_pFrame )
        {
            CComQIPtr<IXStackFrame> spXFrame( m_pFrameInfo->m_pFrame );
            spXFrame->UnInit();
        }
    }
}
